package com.hcj.springcloud.service;

import com.hcj.springcloud.thread.MyCallableThread;
import com.hcj.springcloud.thread.MyRunnableThread;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.*;
import java.math.BigDecimal;
import java.util.concurrent.*;

@Service
@Slf4j
public class GitHubLookupService {
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 在github上面找到用户信息
     *
     * @param user
     * @return
     * @throws InterruptedException
     */
    @Async("taskExecutor")
    public CompletableFuture<String> findUser(String user) throws InterruptedException {
        log.info("looking up {}", user);
        String url = String.format("https://api.github.com/users/%s", user);
        String forObject = restTemplate.getForObject(url, String.class);
        log.info("result--->:{}", forObject);
        Thread.sleep(3000L);
        return CompletableFuture.completedFuture(forObject);
    }



    /**
     * 创建一个可缓存线程池
     *
     * @return
     */
    public ExecutorService newCachedThreadPool() {
        return Executors.newCachedThreadPool();
    }

    /**
     * 创建一个可重用固定个数的线程池
     *
     * @return
     */
    public ExecutorService newFixedThreadPool(Integer num) {
        return Executors.newFixedThreadPool(num);
    }

    /**
     * 创建一个单线程化的线程池，
     * 它只会用唯一的工作线程来执行任务，
     * 保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
     *
     * @return
     */
    public ExecutorService newSingleThreadExecutor() {
        return Executors.newSingleThreadExecutor();
    }

    /**
     * 创建一个定长线程池，支持定时及周期性任务执行——延迟执行
     *
     * @return
     */
    public ScheduledExecutorService newScheduledThreadPool(Integer num) {
        return Executors.newScheduledThreadPool(num);
    }


    // 测试多线程
    public void testMultiThread(ExecutorService executorService) {
        for (int i = 0; i < 15; i++) {
            final int index = i;
            if (executorService instanceof ScheduledExecutorService) {
                ((ScheduledExecutorService) executorService).schedule(new Runnable() {
                    @Override
                    public void run() {
                        log.info("[{}]-->{}\t index:{}", Thread.currentThread().getName(), " ScheduledExecutorService 延迟1秒执行", index);
                    }
                }, 1, TimeUnit.SECONDS);
            } else {
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        log.info("[{}]--->{} \tindex:{}", Thread.currentThread().getName(), "正在被执行... ", index);
                    }
                });
            }
        }
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        GitHubLookupService demo = new GitHubLookupService();
        ExecutorService executorService = demo.newCachedThreadPool();
        demo.testMultiThread(executorService);

        Thread.sleep(1000L);
        log.info("newFixedThreadPool start......");

        executorService = demo.newFixedThreadPool(3);
        demo.testMultiThread(executorService);

        Thread.sleep(1000L);
        log.info("newScheduledThreadPool start......");

        ScheduledExecutorService scheduledExecutorService = demo.newScheduledThreadPool(3);
        demo.testMultiThread(scheduledExecutorService);

        Thread.sleep(1000L);
        log.info("newSingleThreadExecutor start......");

        executorService = demo.newSingleThreadExecutor();
        demo.testMultiThread(executorService);


        // 测试：多线程下的队列
        ArrayBlockingQueue<Runnable> bqList = new ArrayBlockingQueue<>(10);
        // 自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 50, TimeUnit.MICROSECONDS, bqList);

        // 创建3个任务
        MyRunnableThread t1 = new MyRunnableThread();
        MyRunnableThread t2 = new MyRunnableThread();
        MyRunnableThread t3 = new MyRunnableThread();

        executor.execute(t1);
        executor.execute(t2);
        executor.execute(t3);


        // 创建3个有返回值的任务
        MyCallableThread<Integer> myCallableThread1 = new MyCallableThread<>();
        MyCallableThread<Integer> myCallableThread2 = new MyCallableThread<>();
        MyCallableThread<Integer> myCallableThread3 = new MyCallableThread<>();

        Future<Integer> myCallableThread1_returnNum = executor.submit(myCallableThread1);
        Future<Integer> myCallableThread2_returnNum = executor.submit(myCallableThread2);
        Future<Integer> myCallableThread3_returnNum = executor.submit(myCallableThread3);

        log.info("任务1返回值：{}", myCallableThread1_returnNum.get());
        log.info("任务2返回值：{}", myCallableThread2_returnNum.get());
        log.info("任务3返回值：{}", myCallableThread3_returnNum.get());

        // 关闭线程池
        executor.shutdown();


    }
}
